#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

// // 查看系统的环境变量
// int main(int argc,  char* argv[], char* env[])
// {
//     std::cout << "begin................................" << std::endl;
//     int i = 0;
//     while (env[i])
//     {
//         printf("env[%d]: %s\n", i, env[i]);
//         i++;
//     }
//     std::cout << "end.................................." << std::endl;

//     return 0;
// }

// // 测试进程地址空间是虚拟地址  子进程有自己独立的进程地址空间
// int g_val = 100;
// int main()
// {
//     pid_t ret = fork();
//     if (ret < 0)
//     {
//         perror("fork  error");
//         exit(1);
//     }
//     else if (ret == 0)
//     {
//         // 子进程
//         int count = 0;
//         while (count < 5)
//         {
//             printf("我是子进程, pid: %d, ppid:%d, g_val=%d, &g_val=%p\n", getpid(), getppid(), g_val, &g_val);
//             sleep(1);
//             count++;
//             if (count == 5)
//             {
//                 g_val = 200;
//                 printf("g_val已经改变, g_val = %d, &g_val=%p\n", g_val, &g_val);
//             }
//         }
//     }
//     else
//     {
//         // 父进程
//         while (true)
//         {
//             printf("我是父进程, pid: %d, ppid:%d, g_val=%d, &g_val=%p\n", getpid(), getppid(), g_val, &g_val);
//             sleep(1);
//         }
//     }
//     return 0;
// }



// // 进程等待
// int main()
// {
//     pid_t id = fork();
//     if (id < 0)
//     {
//         perror("fork error");
//         exit(1);
//     }
//     else if (id == 0)
//     {
//         // 子进程
//         int i = 0;
//         while (i < 5)
//         {
//             printf("i = %d, 子进程, pid = %d, ppid = %d\n", i, getpid(), getppid());
//             i++;
//             sleep(1);
//         }
//     }
//     else
//     {
//         // 父进程
//         printf("父进程, pid = %d, ppid = %d\n", getpid(), getppid());

//         // // 使用wait接口
//         // pid_t ret = wait(nullptr); // 阻塞式等待
//         // if (ret > 0)
//         // {
//         //     printf("等待子进程成功, ret = %d\n", ret);
//         // }

//         // // 打印出其退出码和收到的信号
//         // int status = 0;
//         // pid_t ret = wait(&status);
//         // if (ret > 0)
//         // {
//         //     printf("等待子进程成功, ret = %d, 子进程的退出码:%d, 子进程的退出信号: %d\n", ret, (status >> 8 & 0x8F), status & 0x7F);
//         // }

//         // // 使用waitpid接口
//         // while (true)
//         // {
//         //     pid_t ret = waitpid(-1, nullptr, 0); // 阻塞式等待
//         //     if (ret > 0)
//         //     {
//         //         printf("等待子进程成功, ret = %d\n", ret);
//         //         break;
//         //     }
//         //     std::cout << "子进程未退出!" << std::endl; // 阻塞式等待是看不到的
//         //     sleep(1);
//         // }

//         // 打印子进程的退出码和退出信号
//         int status = 0;
//         while (true)
//         {
//             pid_t ret = waitpid(id, &status, WNOHANG); // 非阻塞式等待
//             if (ret > 0)
//             {
//                 printf("等待子进程成功, ret = %d, 子进程的退出码:%d, 子进程的退出信号: %d\n", ret, status >> 8 & 0x8F, status & 0x7F);
//                 break;
//             }
//             //std::cout << "子进程未退出!" << std::endl; // 非阻塞式等待是可以看到的
//             sleep(1);
//         }
//     }
//     return 0;
// }



// // 使用 WEXITSTATUS 打印退出码, 使用WIFEXITED 打印退出信号
// int main()
// {
//     pid_t id = fork();
//     if (id < 0)
//     {
//         perror("fork error");
//         exit(1);
//     }
//     else if (id == 0)
//     {
//         // 子进程
//         int cnt = 5;
//         while (cnt > 0)
//         {
//             printf("cnt = %d, 子进程: pid = %d, ppid = %d\n", cnt, getpid(), getppid());
//             cnt--;
//             sleep(1);
//         }
//         exit(12); // 仅用来测试
//     }
//     else
//     {
//         // 父进程
//         printf("父进程, pid() = %d, ppid = %d\n", getpid(), getppid());
//         int status = 0;
//         pid_t ret = waitpid(-1, &status, 0);
//         if (ret > 0)
//         {
//                 if (WEXITSTATUS(status))
//                 {
//                     printf("子进程正常退出, ret = %d, 子进程退出码: %d\n", ret, WEXITSTATUS(status));
//                 }
//                 else
//                 {
//                     printf("子进程异常退出, 退出信号: %d\n", WIFEXITED(status));
//                 }
//         }
//         else  // 等待失败
//         {
//             printf("等待失败\n");
//         }
//     }

//     return 0;
// }





// 非阻塞等待的应用
#include <vector>

typedef void (*handler_t)(); // 函数指针类型
std::vector<handler_t> handlers;

void func1()
{
    std::cout << "这是一个任务1: 正在执行" << std::endl;
}

void func2()
{
    std::cout << "这是一个任务2: 正在执行" << std::endl;
}

void Load() // 把任务放在容器中
{
    std::cout << "开始放置任务!" << std::endl;
    handlers.push_back(func1);
    handlers.push_back(func2);
}

int main()
{
    pid_t id = fork();
    if (id < 0)
    {
        perror("fork error");
        exit(1);
    }
    else if (id == 0)
    {
        // 子进程
        int cnt = 5;
        while (cnt > 0)
        {
            printf("cnt = %d, 子进程: pid = %d, ppid = %d\n", cnt, getpid(), getppid());
            cnt--;
            sleep(1);
        }
        exit(12); // 仅用来测试
    }
    else
    {
        // 父进程
        int quit = 0;
        while (!quit)
        {
            int status = 0;
            pid_t ret = waitpid(-1, &status, WNOHANG);
            if (ret > 0)
            {
                if (WEXITSTATUS(status))
                {
                    printf("子进程正常退出, ret = %d, 子进程退出码: %d\n", ret, WEXITSTATUS(status));
                }
                else
                {
                    printf("子进程异常退出, 退出信号: %d\n", WIFEXITED(status));
                }
                quit = 1;
            }
            else if (ret == 0) // 等待成功, 但子进程并未成功
            {
                printf("等待成功, 但子进程并未退出, 可以处理下其他的事情!\n");
                if (handlers.empty())
                {
                    Load();
                }
                for (auto e : handlers)
                {
                    e();
                }
            }
            else
            {
                printf("wait失败\n");
                quit = 1;
            }

            sleep(1);
        }
    }
    return 0;
}
